/*
 * Copyright 2010 Askar Kalykov, oxygene.core@gmail.com
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.oxygenecore.processor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Askar Kalykov
 *         Date: 11.09.2010
 *         Time: 16:56:10
 */
public class ExecutionContextImpl implements ExecutionContext {

    private ExecutionContext parentExecutionContext;


    public ExecutionContextImpl(ExecutionContext parentExecutionContext) {
        this.parentExecutionContext = parentExecutionContext;
    }

    public ExecutionContext getParentScope() {
        return parentExecutionContext;
    }

    public Variable getVariable(String name) throws CalculationException {
        return index.getVariable(name);
    }

    public void addVariable(Variable variable) throws CalculationException {
        index.addVariable(variable);
    }

    public void destroy() {
        index.destroy();
    }

    public List<Variable> getVariablesByType(Class type) {
        return index.getVariablesByType(type);
    }

    private Index index = new Index();

    private class Index {
        private Map<String, Variable> byName = new HashMap<String, Variable>();
        private Map<Class, List<Variable>> byClass = new HashMap<Class, List<Variable>>();

        public Variable getVariable(String name) throws CalculationException {
            if (name == null){
                throw new NullPointerException("name");
            }
            Variable variable = byName.get(name);
            if (variable == null){
                if (parentExecutionContext == null){
                    throw new UnknownVariableException(name);
                } else {
                    return parentExecutionContext.getVariable(name);
                }
            }
            return variable;

        }

        public void addVariable(Variable variable) throws VariableAlreadyExistsException {
            if (variable == null){
                throw new NullPointerException("variable");
            }
            if (byName.containsKey(variable.getName())){
                throw new VariableAlreadyExistsException(variable.getName());
            }
            byName.put(variable.getName(), variable);
            List<Variable> variableList = byClass.get(variable.getDeclarationClass());
            if (variableList == null){
                variableList = new ArrayList<Variable>();
                byClass.put(variable.getDeclarationClass(), variableList);
            }
            variableList.add(variable);
        }

        public List<Variable> getVariablesByType(Class type) {
            List<Variable> variableList = byClass.get(type);
            if (variableList == null){
                variableList = new ArrayList<Variable>();
                byClass.put(type, variableList);
            }
            return variableList;
        }


        public void destroy(){
            byName.clear();

        }
    }
}
